原文在这里. 有段时间不看了, 有些忘了,有些地方还有一定的加深.
什么是 React stateless function?
es6的语法
| 1 | class List extends React.Component { | 
简单的 javascripg函数也可以!
| 1 | //Stateless function syntax | 
彻底的模板,没有自己任何的数据,也没有生命周期方法. 纯粹依赖于输入.
首先来定义一个 App Container
目的是最为一个函数接收 app sate 对象
| 1 | import React from 'react'; | 
在纯函数中,state 必须要在外部管理,然后以 props 的形式传递给组件.
下面看看这个解释的例子
Stateless Timer component
简单的 timer 组件只接受 secondsElapsed 参数:
| 1 | import React from 'react'; | 
添加到 APP 中
| 1 | import React from 'react'; | 
最后创建main.js 文件,启动渲染过程
| 1 | import App from './components/app'; //导入容器组件 | 
对于上面的代码, 变化的是组件的 state, 渲染的目标元素是一直不变的, 所以我们用柯理化配置好一个工厂函数
| 1 | //闭包再工作! | 
柯理化返回的函数,等待传入 props
| 1 | (props) => ReactDOM.render(...) | 
只要 State发生变化,我们需要渲染时,只需要传递 state 就可以了
| 1 | setInterval(() => { | 
每一秒钟, secondsElapsed 属性会递增1, 然后作为参数传递给 render 函数
现在可以实现 Redux 风格的 reduce 函数, reduce式的函数不能突变当前值
| 1 | currentState->newState | 
使用 Radma 的 Lenses 来实现
| 1 | const secondsElapsedLens = R.lensProp('secondsElapsed'); | 
首先创建 Lens:
| 1 | const secondsElapsedLens = R.lensProp('secondsElapsed'); | 
lens可以聚焦于给定的属性,不会针对特定的对象, 所以可以重用.
- View
| 1 | R.view(secondsElapsedLens, { secondsElapsed: 10 }); //=> 10 | 
- Set
| 1 | R.set(secondsElapsedLens, 11, { secondsElapsed: 10 }); //=> 11 | 
- 用给定的函数 Set
| 1 | R.over(secondsElapsedLens, R.inc, { secondsElapsed: 10 }); //=> 11 | 
inSecondElapsed  reducer 是一个偏应用函数(partial application),
这一行
| 1 | const incSecondsElapsed = R.over(secondsElapsedLens, R.inc); | 
会返回一个新的函数,一旦用appState 调用, 就会应用 R.inc在 lensed prop secondElapsed 上.
| 1 | appState=incSecondElapsed(appState) | 
组合 React stateless components
开篇提到,React 组件可以作为函数, 那么可以用 R.compose来 compose 这些函数吗?
当然是可以的
用 React.createClass 是这样的:
| 1 | const TodoList = React.createClass({ | 
现在问题是: TodoList 可以由小的可重用部分 composition 而成吗? 可以的. 可以分为三个更小的组件
- 容器组件
| 1 | const Container = children => (<div className="panel panel-default"> | 
- 列表组件
| 1 | const List = children => (<ul> | 
- 列表项组件
| 1 | const ListItem = ({ id, text }) => (<li key={id}> | 
现在一步一动,看看每一步的输出
| 1 | Container(<h1>Hello World!</h1>); | 
- mapTodos 可以有更简单的模式
| 1 | //This | 
- const mapTodos = R.map(ListItem); Ramda 函数式自动柯理化的,所以代码是这样的, 等待传递数据数组,返回的数组的形式是
- {data.item} 组成的数组
完整的 TodoList 的代码就是
| 1 | import React from 'React'; | 
工厂配置好了,就等数据了
- 模拟一下 appState 的 todo 数据
| 1 | let appState = { | 
- 在 App 组件中添加 TodoList 组件作为子组件
| 1 | import TodoList from './todo-list'; | 
TodoList组件期待的参数是一个todos数组,
| 1 | <TodoList todos={appState.todos} /> | 
React stateless component是作为函数的,所以我们也可以传递参数
| 1 | TodoList({todos: appState.todos}); | 
最好是传递单个参数,所以这种情况,再改进一下
| 1 | const TodoList = R.compose(Container, List, R.map(ListItem), R.prop('todos')); | 
调用就直接改为:
| 1 | TodoList(appState) | 
结束